1
|
|
|
import redis from 'redis' |
2
|
|
|
import Limiter from 'ratelimiter' |
3
|
|
|
import owasp from 'owasp-password-strength-test' |
4
|
|
|
import bcrypt from 'bcrypt-nodejs' |
5
|
|
|
import Cookies from 'cookies' |
6
|
|
|
import jwt from 'jwt-simple' |
7
|
|
|
|
8
|
|
|
import { |
9
|
|
|
User |
10
|
|
|
,config |
11
|
|
|
,coreUtils |
12
|
|
|
} from '../../cli' |
13
|
|
|
|
14
|
|
|
export function checkSameEmail(data) { |
15
|
|
|
var emailAlreadyUsed = false |
16
|
|
|
var bdd = User.manager.instance.get() |
17
|
|
|
for (var i = 0, len = bdd.length; i < len; i++) { |
18
|
|
|
var user = bdd[i] |
19
|
|
|
if (user.email === data.email && parseInt(user.id) !== parseInt(data.id)) { |
20
|
|
|
emailAlreadyUsed = true |
21
|
|
|
} |
22
|
|
|
} |
23
|
|
|
|
24
|
|
|
if (emailAlreadyUsed === true) { |
25
|
|
|
return { |
26
|
|
|
success:0, |
27
|
|
|
message: 'Email adress already exist' |
28
|
|
|
} |
29
|
|
|
}else { |
30
|
|
|
return { |
31
|
|
|
success:1 |
32
|
|
|
} |
33
|
|
|
} |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
export function getRole(data) { |
37
|
|
|
var roles = config.users.roles |
38
|
|
|
Array.prototype.forEach.call(roles, (role) => { |
39
|
|
|
if(role.name === data.role) { |
40
|
|
|
data.role = role |
41
|
|
|
} |
42
|
|
|
}) |
43
|
|
|
|
44
|
|
|
return data |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
export function commonPassword(data) { |
48
|
|
|
var owaspConfig = config.users.owasp |
49
|
|
|
owasp.config(owaspConfig) |
50
|
|
|
var sameAsUser = (typeof owaspConfig.sameAsUser !== 'undefined' && owaspConfig.sameAsUser !== null) ? owaspConfig.sameAsUser : true |
51
|
|
|
var mostCommon = (typeof owaspConfig.mostCommon !== 'undefined' && owaspConfig.mostCommon !== null) ? owaspConfig.mostCommon : true |
52
|
|
|
var mostCommonPassword = config.users.mostCommonPassword |
53
|
|
|
owasp.tests.required.push(function(password) { |
54
|
|
|
if (mostCommon && coreUtils.array.contains(mostCommonPassword, password.toLowerCase())) { |
|
|
|
|
55
|
|
|
return 'the password used is too common.' |
56
|
|
|
} |
57
|
|
|
}) |
58
|
|
|
|
59
|
|
|
var currentUserName = data.username |
60
|
|
|
owasp.tests.required.push(function(password) { |
61
|
|
|
var username = currentUserName |
62
|
|
|
var shouldTest = sameAsUser |
63
|
|
|
|
64
|
|
|
if(shouldTest) { |
|
|
|
|
65
|
|
|
if (password.toLowerCase() === username.toLowerCase()) { |
66
|
|
|
return 'username and password must be different.' |
67
|
|
|
} |
68
|
|
|
if (password.toLowerCase() === username.toLowerCase().split('').reverse().join('')) { |
|
|
|
|
69
|
|
|
return 'username and password must be different, not just inverted.' |
70
|
|
|
} |
71
|
|
|
} |
72
|
|
|
}) |
73
|
|
|
|
74
|
|
|
var res = owasp.test(data.password) |
75
|
|
|
|
76
|
|
|
if(typeof res.errors !== 'undefined' && res.errors !== null |
77
|
|
|
&& res.errors.length > 0) { |
78
|
|
|
var message = '' |
79
|
|
|
Array.prototype.forEach.call(res.errors, (error) => { |
80
|
|
|
message += error + '<br />' |
81
|
|
|
}) |
82
|
|
|
return { |
83
|
|
|
success:0, |
84
|
|
|
message: message |
85
|
|
|
} |
86
|
|
|
}else { |
87
|
|
|
return { |
88
|
|
|
success:1 |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
export function encryptPassword(numb, password) { |
94
|
|
|
var salt = bcrypt.genSaltSync(numb) |
95
|
|
|
return bcrypt.hashSync(password, salt) |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
export function getUserRoutes(workflow) { |
99
|
|
|
var routes = config.users.routes |
100
|
|
|
var userRoles = [] |
101
|
|
|
Array.prototype.forEach.call(Object.keys(routes), (role) => { |
102
|
|
|
if(role === workflow) { |
103
|
|
|
userRoles = routes[role] |
104
|
|
|
} |
105
|
|
|
}) |
106
|
|
|
|
107
|
|
|
return userRoles |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
|
111
|
|
|
export function findSync(id) { |
112
|
|
|
var bdd = User.manager.instance.get() |
113
|
|
|
for (var i = 0, len = bdd.length; i < len; i++) { |
114
|
|
|
var user = bdd[i] |
115
|
|
|
if (parseInt(user.id) === parseInt(id)) { |
116
|
|
|
return user |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
return null |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
export function find(id, done) { |
123
|
|
|
var bdd = User.manager.instance.get() |
124
|
|
|
for (var i = 0, len = bdd.length; i < len; i++) { |
125
|
|
|
var user = bdd[i] |
126
|
|
|
if (parseInt(user.id) === parseInt(id)) { |
127
|
|
|
return done(null, user) |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
return done(null, null) |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
export function findByUsername(username, done) { |
134
|
|
|
var bdd = User.manager.instance.get() |
135
|
|
|
for (var i = 0, len = bdd.length; i < len; i++) { |
136
|
|
|
var user = bdd[i] |
137
|
|
|
if (user.username === username) { |
138
|
|
|
return done(null, user) |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
return done(null, null) |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
export function findByEmail(email, done) { |
145
|
|
|
var bdd = User.manager.instance.get() |
146
|
|
|
for (var i = 0, len = bdd.length; i < len; i++) { |
147
|
|
|
var user = bdd[i] |
148
|
|
|
if (user.email === email) { |
149
|
|
|
return done(null, user) |
150
|
|
|
} |
151
|
|
|
} |
152
|
|
|
return done(null, null) |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
export function findByResetPasswordToken(resetPasswordToken, done) { |
156
|
|
|
var bdd = User.manager.instance.get() |
157
|
|
|
for (var i = 0, len = bdd.length; i < len; i++) { |
158
|
|
|
var user = bdd[i] |
159
|
|
|
if (user.resetPasswordToken === resetPasswordToken) { |
160
|
|
|
return done(null, user) |
161
|
|
|
} |
162
|
|
|
} |
163
|
|
|
return done(null, null) |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
export function isValid(user, password) { |
167
|
|
|
if(user.actif === 1) { |
168
|
|
|
if(bcrypt.compareSync(password, user.password)) { |
169
|
|
|
return true |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
return false |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
export function decodeUser(req, res) { |
176
|
|
|
var decoded = {} |
177
|
|
|
var token = User.utils.getTokenFromCookies(req, res) |
178
|
|
|
if(typeof token !== 'undefined' && token !== null && token !== '') { |
179
|
|
|
try { |
180
|
|
|
var secret = config.users.secret |
181
|
|
|
decoded = jwt.decode(token, secret) |
182
|
|
|
} catch (err) {} |
|
|
|
|
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
return decoded |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
export function getTokenFromCookies(req, res) { |
189
|
|
|
var cookies = new Cookies(req, res, { |
190
|
|
|
secure: config.cookie.secure |
191
|
|
|
}) |
192
|
|
|
return cookies.get('x-access-token') |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
export function isAbeRestrictedUrl(currentRoute) { |
196
|
|
|
if( currentRoute.indexOf('/abe/users/forgot') > -1 |
197
|
|
|
|| currentRoute.indexOf('/abe/users/login') > -1 |
198
|
|
|
|| currentRoute.indexOf('/abe/users/reset') > -1 |
199
|
|
|
|| !/^\/abe\//.test(currentRoute)) { |
200
|
|
|
return false |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
return true |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
export function isUserAllowedOnRoute(workflow, currentRoute) { |
207
|
|
|
var isAllowed = false |
208
|
|
|
|
209
|
|
|
if (config.users.enable) { |
210
|
|
|
if( currentRoute.indexOf('/abe/users/forgot') > -1 || currentRoute.indexOf('/abe/users/login') > -1 || !/^\/abe/.test(currentRoute)) { |
211
|
|
|
return true |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
if (currentRoute.indexOf('abe/') === -1) { |
215
|
|
|
isAllowed = true |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
if (workflow != null) { |
219
|
|
|
var routes = config.users.routes |
220
|
|
|
if(typeof routes[workflow] !== 'undefined' && routes[workflow] !== null) { |
221
|
|
|
Array.prototype.forEach.call(routes[workflow], (route) => { |
222
|
|
|
var reg = new RegExp(route) |
223
|
|
|
if(reg.test(currentRoute)) { |
224
|
|
|
isAllowed = true |
225
|
|
|
} |
226
|
|
|
}) |
227
|
|
|
} |
228
|
|
|
} |
229
|
|
|
}else { |
230
|
|
|
isAllowed = true |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
return isAllowed |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
export function getAll() { |
237
|
|
|
return User.manager.instance.get() |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
export function getUserWorkflow(status) { |
241
|
|
|
var flows = [] |
242
|
|
|
|
243
|
|
|
function addFlow (flow, type, action) { |
244
|
|
|
type = (type != null) ? type : flow |
245
|
|
|
return { |
246
|
|
|
status: flow, |
247
|
|
|
url: `/abe/operations/${action}/${type}` |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
if (config.users.enable) { |
252
|
|
|
var found = null |
253
|
|
|
Array.prototype.forEach.call(config.users.workflow, (flow) => { |
254
|
|
|
|
255
|
|
|
if (found != null) { |
256
|
|
|
flows.push(addFlow(flow, flow, 'submit')) |
257
|
|
|
found = null |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
if (status == flow) { |
261
|
|
|
found = flow |
262
|
|
|
if (flow != 'draft' && flow != 'publish') { |
263
|
|
|
flows.push(addFlow('reject', flow, 'reject')) |
264
|
|
|
} |
265
|
|
|
if (flow == 'publish') { |
266
|
|
|
flows.push(addFlow('edit', 'draft', 'edit')) |
267
|
|
|
}else { |
268
|
|
|
flows.push(addFlow('save', flow, 'edit')) |
269
|
|
|
} |
270
|
|
|
} |
271
|
|
|
}) |
272
|
|
|
if (found != null) { |
273
|
|
|
flows.push(addFlow('save', 'publish', 'submit')) |
274
|
|
|
} |
275
|
|
|
}else { |
276
|
|
|
flows = [addFlow('draft', 'draft', 'submit'), addFlow('publish', 'publish', 'submit')] |
277
|
|
|
} |
278
|
|
|
return flows |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
export function loginLimitTry(username) { |
282
|
|
|
var p = new Promise((resolve) => { |
283
|
|
|
var isNexted = false |
284
|
|
|
try { |
285
|
|
|
var limiterConfig = config.users.limiter |
286
|
|
|
|
287
|
|
|
var client = redis.createClient() |
288
|
|
|
client.on('error', function() { |
289
|
|
|
if (!isNexted) { |
290
|
|
|
isNexted = true |
291
|
|
|
resolve() |
292
|
|
|
} |
293
|
|
|
}) |
294
|
|
|
|
295
|
|
|
var limit = new Limiter({ |
296
|
|
|
id: username, |
297
|
|
|
db: client, |
298
|
|
|
duration: limiterConfig.duration, |
299
|
|
|
max: limiterConfig.max |
300
|
|
|
}) |
301
|
|
|
|
302
|
|
|
limit.get(function(err, limit) { |
303
|
|
|
if (err) { |
304
|
|
|
resolve() |
305
|
|
|
}else { |
306
|
|
|
resolve(limit) |
307
|
|
|
} |
308
|
|
|
}) |
309
|
|
|
}catch(e) { |
310
|
|
|
resolve() |
311
|
|
|
} |
312
|
|
|
}) |
313
|
|
|
|
314
|
|
|
return p |
315
|
|
|
} |
This check looks for functions where a
return
statement is found in some execution paths, but not in all.Consider this little piece of code
The function
isBig
will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly returnundefined
.This behaviour may not be what you had intended. In any case, you can add a
return undefined
to the other execution path to make the return value explicit.